package com.huitone.smspfm.redis.impl;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.huitone.smspfm.redis.BaseAbstractOpts;
import com.huitone.smspfm.redis.model.AppCanstant;

/**
 * 
* @Title: SetOpts.java 
* @Package com.huitone.smspfm.redis.impl 
* @Description: TODO(用一句话描述该文件做什么) 
* @author ybliang   
* @date 2017年3月15日 上午10:42:58 
* @version V1.0
 */
public class SetOpts extends BaseAbstractOpts<String, Object>{
	
	private static final Logger logger = LogManager.getLogger(SetOpts.class);
	
	public long add(String key, Object... values) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		long result = 0;
		
		do {
			try {
				curTryTimes ++;
				result = redisTemplate.opsForSet().add(key, values);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "add(String key, Object... values)");
				json.put("key", key);
				JSONArray arrayValues = new JSONArray();
				if (values != null && values.length > 0) {
					for (int i = 0; i < values.length; i++) {
						arrayValues.add(values[i]);
					}
				}
				json.put("values", arrayValues);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		return result;
	}
	
	public Long remove(String key, Object... value) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		long result = 0;
		
		do {
			try {
				curTryTimes ++;
				result = redisTemplate.opsForSet().remove(key, value);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "remove(String key, Object... value)");
				json.put("key", key);
				JSONArray arrayValues = new JSONArray();
				if (value != null && value.length > 0) {
					for (int i = 0; i < value.length; i++) {
						arrayValues.add(value[i]);
					}
				}
				json.put("values", arrayValues);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		return result;
		
	}
	
	public Long remove(String key, ScanOptions options){
		
		List<Object> list = new ArrayList<>();
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		long result = 0;
		
		do {
			try {
				curTryTimes ++;
				
				Cursor<Object> scan = redisTemplate.opsForSet().scan(key, options);
				
				while(scan.hasNext()) {
					list.add(scan.next());
				}
				
				try {
					scan.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				if (!list.isEmpty()) {
					redisTemplate.opsForSet().remove(key, list.toArray());
				} 
				
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "remove(String key, ScanOptions options)");
				json.put("key", key);				
				json.put("options", options.toOptionString());
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		return result;
		
	}
	
	public Cursor<Object> scan(String key, ScanOptions options) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		Cursor<Object> result = null;
		
		do {
			try {
				curTryTimes ++;
				result = redisTemplate.opsForSet().scan(key, options);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "scan(String key, ScanOptions options)");
				json.put("key", key);				
				json.put("options", options.toOptionString());
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		return result;
	}
	
	public Object pop(String key) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		Object result = null;
		
		do {
			try {
				curTryTimes ++;
				result = redisTemplate.opsForSet().pop(key);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "pop(String key)");
				json.put("key", key);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		return result;
		
	}
	
	public boolean isMember(String key, Object o) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		Boolean result = false;
		
		do {
			try {
				curTryTimes ++;
				result = redisTemplate.opsForSet().isMember(key, o);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "isMember(String key, Object o)");
				json.put("key", key);
				json.put("object", o);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		return result;
	}

}
